package com.sayyi.demo.micro.storage.api.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.sayyi.demo.micro.storage.api.StorageApi;
import com.sayyi.demo.micro.storage.convertor.StorageConvertor;
import com.sayyi.demo.micro.storage.domain.UpdateStorageRequest;
import com.sayyi.demo.micro.storage.entity.StorageTbl;
import com.sayyi.demo.micro.storage.service.IStorageTblService;
import com.sayyi.demo.micro.storage.service.StorageTccService;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboService;
import org.redisson.api.RBucket;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.concurrent.TimeUnit;

@DubboService(version = "1.0.0",interfaceClass = StorageApi.class)
@Slf4j
public class StorageApiImpl implements StorageApi {

    @Autowired
    private StorageConvertor storageConvertor;

    @Autowired
    private IStorageTblService storageTblService;

    @Autowired
    private StorageTccService service;

    @Autowired
    private RedissonClient redissonClient;

    @Override
    public boolean updateStorage(UpdateStorageRequest updateStorageRequest) {
        RLock lock = redissonClient.getLock(updateStorageRequest.getCommodityCode());
        boolean locked = false;
        try {
            locked = lock.tryLock(1000, TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if (!locked) {
            throw new RuntimeException("加锁失败");
        }
        try {
            // 幂等
            RBucket<Boolean> bucket = redissonClient.getBucket("order_id_" + updateStorageRequest.getOrderId());
            if (!bucket.trySet(true, 5 * 60 * 1000, TimeUnit.MILLISECONDS)) {
                log.info("对应订单的商品库存已经执行过了[{}]", updateStorageRequest.getOrderId());
                return false;
            }
            // 乱序
            RBucket<Boolean> compensateBucket = redissonClient.getBucket("order_compensate_id_" + updateStorageRequest.getOrderId());
            if (Boolean.TRUE.equals(compensateBucket.get())) {
                log.warn("回滚补偿已经提前执行，不进行库存扣减操作[{}]", updateStorageRequest.getOrderId());
                return false;
            }
            log.info("扣减库存[{}]", updateStorageRequest);
            QueryWrapper<StorageTbl> codeQuery = new QueryWrapper<>();
            codeQuery.eq("commodity_code", updateStorageRequest.getCommodityCode());
            StorageTbl storageTbl = storageTblService.getOne(codeQuery);
            if (storageTbl == null) {
                throw new RuntimeException("获取库存信息失败");
            }
            if (storageTbl.getCount() < updateStorageRequest.getCount()) {
                throw new RuntimeException("库存扣减");
            }
            storageTbl.setCount(storageTbl.getCount() - updateStorageRequest.getCount());
            storageTblService.updateById(storageTbl);
            log.info("扣减库存完毕[{}]", storageTbl.getCount());
            return true;
        } finally {
            lock.unlock();
        }
    }

    @Override
    public boolean compensateStorage(UpdateStorageRequest updateStorageRequest) {
        RLock lock = redissonClient.getLock(updateStorageRequest.getCommodityCode());
        boolean locked = false;
        try {
            locked = lock.tryLock(1000, TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if (!locked) {
            throw new RuntimeException("加锁失败");
        }
        try {
            // 幂等处理
            RBucket<Boolean> bucket = redissonClient.getBucket("order_compensate_id_" + updateStorageRequest.getOrderId());
            if (!bucket.trySet(true, 5 * 60 * 1000, TimeUnit.MILLISECONDS)) {
                log.info("对应订单的商品库存已经回滚过了[{}]", updateStorageRequest.getOrderId());
                return false;
            }
            // 乱序
            RBucket<Boolean> idBucket = redissonClient.getBucket("order_id_" + updateStorageRequest.getOrderId());
            if (!Boolean.TRUE.equals(idBucket.get())) {
                log.warn("回滚补偿乱序，不进行库存回滚操作[{}]", updateStorageRequest.getOrderId());
                return false;
            }

            log.info("增加库存[{}]", updateStorageRequest);
            QueryWrapper<StorageTbl> codeQuery = new QueryWrapper<>();
            codeQuery.eq("commodity_code", updateStorageRequest.getCommodityCode());
            StorageTbl storageTbl = storageTblService.getOne(codeQuery);
            if (storageTbl == null) {
                return true;
            }
            storageTbl.setCount(storageTbl.getCount() + updateStorageRequest.getCount());
            return storageTblService.updateById(storageTbl);
        } finally {
            lock.unlock();
        }
    }

    @Override
    public boolean updateByTcc(UpdateStorageRequest updateStorageRequest) {
        return service.deductStorage(null, updateStorageRequest);
    }
}
